package com.biz.primus.ms.product.service;

import com.biz.primus.base.vo.*;
import com.biz.primus.base.vo.commodity.ProductListItemVo;
import com.biz.primus.commodity.vo.frontend.ProductDetailRequestVo;
import com.biz.primus.commodity.vo.frontend.ProductDetailResult;
import com.biz.primus.commodity.vo.frontend.ProductRecItemsVo;
import com.biz.primus.commodity.vo.frontend.RecommendProductReqVo;
import com.biz.primus.common.utils.JsonUtils;
import com.biz.primus.ms.product.interfaces.ProductPrototype;
import com.biz.primus.ms.product.trans.ProductPrototype2ProductDetailResult;
import com.biz.primus.ms.product.trans.ProductPrototype2ProductListItemVo;
import com.biz.primus.product.vo.OrderProductInfoRespVo;
import com.biz.primus.product.vo.OrderProductReqVo;
import com.biz.primus.product.vo.SecProductInfoReqVo;
import com.biz.primus.product.vo.SecProductInfoRespVo;
import com.biz.primus.search.vo.search.ProductSearchResultVo;
import com.biz.primus.search.vo.search.SearchProductRequestVo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

/**
 * @author jiangnan
 * @Description: TODO
 * @create 2017-10-12-下午3:18
 */
@Slf4j
@Service
public class ProductService extends AbstractProductService {

    @Autowired
    private ProductServiceHelper productServiceHelper;

    @Autowired
    private ProductRecommendService productRecommendService;

    public ProductDetailResult productDetail(ProductDetailRequestVo vo) {
        log.debug("productDetail reqVo:{}", vo);
        ProductPrototype productPrototype = this.builder(vo.getProductCode())
                .buildPrice(vo.getDepotCode(), vo)
                .builStock(vo.getDepotCode())
//                .buildCustomModel()
                .buildPromotionBasicInfo(vo)
                .buildLimitation(vo.getLatitude(), vo.getLongitude(), vo.getDepotLat(), vo.getDepotLon())
                .build();
        return new ProductPrototype2ProductDetailResult().apply(productPrototype);
    }

    public List<ProductListRestVo> recommendProducts(RecommendProductReqVo reqVo) {
        log.debug("recommendProducts reqVo{}", reqVo);
        ProductRecItemsVo productRec = productRecommendService.recommend(reqVo.getProductRecommend(), reqVo.getProductCode(),
                reqVo.getMemberId() == null ? null : reqVo.getMemberId().toString());
        log.debug("recommend resp {}", productRec);
        List<ProductPrototype> productPrototypes = this.multiBuilder(productRec.getProductCodes())
                .buildPrices(reqVo.getDepotCode(), reqVo)
                .buildStocks(reqVo.getDepotCode())
                .buildPromotionTag()
                .buildLimitation(reqVo.getUserLat(), reqVo.getUserLon(), reqVo.getDepotLat(), reqVo.getDepotLon())
                .build();
        List<ProductListItemVo> collect = getProductListItemVos(productPrototypes,reqVo.getDepotProduct());
        collect.stream().filter(Objects::nonNull).forEach(p -> p.setTraceId(productRec.getTraceId()));
        log.debug("recommendProducts respVo:{}", JsonUtils.obj2Json(collect));
        return collect.stream().map(new ProductListItemVo2ProductListRestVo()).filter(Objects::nonNull).collect(toList());
    }

    /**
     * 秒杀商品详情
     *
     * @param secProductInfoReqVo
     * @return
     */
    public List<SecProductInfoRespVo> secProductInfo(SecProductInfoReqVo secProductInfoReqVo) {
        log.debug("secProductInfo reqVo:{}", secProductInfoReqVo);
        List<ProductPrototype> productPrototypes = this.multiBuilder(secProductInfoReqVo.getProductCodes())
                .buildPrices(null).build();
        List<ProductListItemVo> collect = getProductListItemVos(productPrototypes,Boolean.FALSE);
        if (CollectionUtils.isEmpty(collect)) {
            return Lists.newArrayList();
        }
        List<SecProductInfoRespVo> respVos = Lists.newArrayList();
        for (ProductListItemVo index : collect) {
            if (index == null) {
                respVos.add(null);
            } else {
                respVos.add(new SecProductInfoRespVo(index.getBase(), index.getProductPriceVo().getVirtualPrice()));
            }
        }
        return respVos;
    }

    public PageResult<ProductListRestVo> searchProducts(SearchProductRequestVo reqVo) {
        log.debug("searchProducts reqVo:{}", reqVo);
        ProductSearchResultVo<ProductSearchResultEntityVo> searchResult = this.doSearch(reqVo);
        List<String> productCodes = searchResult.getItems().stream().map(ProductSearchResultEntityVo::getProductCode).collect(toList());
        List<ProductPrototype> productPrototypes = this.multiBuilder(productCodes)
                .buildPrices(reqVo.getDepotCode(), reqVo)
                .buildStocks(reqVo.getDepotCode())
                .buildPromotionTag()
                .buildLimitation(reqVo.getUserLat(), reqVo.getUserLon(), reqVo.getDepotLat(), reqVo.getDepotLon())
                .build();
        List<ProductListItemVo> collect = getProductListItemVos(productPrototypes,reqVo.getDepotProduct());
        List<ProductListRestVo> list = collect.stream().map(new ProductListItemVo2ProductListRestVo()).filter(Objects::nonNull).collect(toList());
        PageResult<ProductListRestVo> respVo = new PageResult<>();
        respVo.setContent(list);
        respVo.setCurrentPage(reqVo.getPage());
        respVo.setTotalPage(searchResult.getTotalPages());
        log.debug("searchProducts resp:{}", JsonUtils.obj2Json(respVo));
        return respVo;
    }

    /**
     *
     * @param productPrototypes
     * @param depotProduct 是否立即送
     * @return
     */
    private List<ProductListItemVo> getProductListItemVos(List<ProductPrototype> productPrototypes,Boolean depotProduct) {
        if (depotProduct == null){
            depotProduct = Boolean.FALSE;
        }
//      立即送 过滤门店价格不合法的原型
        Stream<ProductListItemVo> productListItemVoStream = productPrototypes.stream()
                .map(p -> new ProductPrototype2ProductListItemVo().apply(p)).filter(Objects::nonNull);
        if (depotProduct){
            return productListItemVoStream.filter(ProductListItemVo::depotPriceFilter).filter(ProductListItemVo::depotStockFilter).collect(toList());
        }
        return productListItemVoStream.collect(toList());
    }

    public List<OrderProductInfoRespVo> orderProduct(OrderProductReqVo reqVo) {
        List<ProductPrototype> productPrototypes = this.multiBuilder(reqVo.getProductCode())
                .buildLimitation(reqVo.getUserLatitude(),reqVo.getUserLongitude(),reqVo.getDepotLatitude(),reqVo.getDepotLongitude())
                .buildPrices(reqVo.getDepotCode(), reqVo)
                .buildStocks(reqVo.getDepotCode())
                .build();
        List<OrderProductInfoRespVo> respVos = productPrototypes.stream().filter(Objects::nonNull).map((p) -> {
            OrderProductInfoRespVo respVo = new OrderProductInfoRespVo();
            respVo.setProductBaseVo(p.getProductBaseVo());
            respVo.setProductPriceVo(p.getProductPriceVo());
            respVo.setProductStockVo(p.getProductStockVo());
            respVo.setPredictTime(p.getPredictTime());
            respVo.setSpecialOfferPromotion(p.getProductSpecialOfferPromotion());
            return respVo;
        }).collect(toList());
        return respVos;
    }

    public List<ProductListRestVo> indexProduct(OrderProductReqVo reqVo) {
        List<ProductPrototype> productPrototypes = this.multiBuilder(reqVo.getProductCode())
                .buildPrices(reqVo.getDepotCode(), reqVo)
                .buildStocks(reqVo.getDepotCode())
                .buildLimitation(reqVo.getUserLatitude(),reqVo.getUserLongitude(),reqVo.getDepotLatitude(),reqVo.getDepotLongitude())
                .buildPromotionTag()
                .build();
        List<ProductListItemVo> collect = getProductListItemVos(productPrototypes,Boolean.TRUE);
        return collect.stream().map(new ProductListItemVo2ProductListRestVo()).filter(Objects::nonNull).collect(toList());
    }
}
